package com.wzx.common.util.token;

import com.alibaba.fastjson.JSON;
import com.wzx.common.constants.SystemConstants;
import com.wzx.common.pojo.UserToken;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;

/**
 * @author wzx
 * @version 1.0
 * @date 2022/1/29 - 14:53
 * @description jwt token工具
 */
@Slf4j
public class AppJwtUtil {
    /**
     * TOKEN的有效期一天（S）
     * 单位：秒
     * 60秒 * 60分钟 = 1小时
     */
    public static final int TOKEN_TIME_OUT = 60 * 60 * 24 * 7;

    /**
     * 加密KEY
     */
    private static final String TOKEN_ENCRYPT_KEY = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY";


    /**
     * 令牌中用户信息的key
     */
    public static final String USER_TOKEN_KEY = "usertoken";


    /**
     * @param userToken 用户的信息
     * @return
     */
    public static String createTokenUserToken(UserToken userToken) {
        Map<String, Object> claimMaps = new HashMap<>();
        //当前时间
        long currentTime = System.currentTimeMillis();
        //过期时间
        long expiration = currentTime + TOKEN_TIME_OUT * 1000;
        //设置过期时间到usertoken中
        userToken.setExpiration(expiration);
        //用户信息
        claimMaps.put(AppJwtUtil.USER_TOKEN_KEY, JSON.toJSONString(userToken));
        return Jwts.builder()
                //令牌的唯一标识 uuid生成
                .setId(UUID.randomUUID().toString())
                //签发时间
                .setIssuedAt(new Date(currentTime))
                //数据压缩方式
                .compressWith(CompressionCodecs.GZIP)
                //设置秘钥
                //加密方式
                .signWith(SignatureAlgorithm.HS256, generalKey())
                //过期一个小时
                .setExpiration(new Date(expiration))
                .addClaims(claimMaps) //cla信息
                //生成
                .compact();
    }

    /**
     * 解析用户信息 并获取过期时间
     *
     * @param token
     * @return
     */
    public static UserToken getUserToken(String token) {
        UserToken userToken = null;
        try {
            userToken = JSON.parseObject(getJws(token).getBody().get(AppJwtUtil.USER_TOKEN_KEY).toString(), UserToken.class);
        } catch (Exception e) {
            log.error("解析用户信息错误！！！", e);
        }
        return userToken;
    }


    /**
     * 获取token中的claims信息
     *
     * @param token
     * @return
     */
    private static Jws<Claims> getJws(String token) {
        return Jwts.parser()
                .setSigningKey(generalKey())
                .parseClaimsJws(token);
    }

    /**
     * 获取payload body信息
     *
     * @param token
     * @return
     */
    public static Claims getClaimsBody(String token) {
        try {
            return getJws(token).getBody();
        } catch (ExpiredJwtException e) {
            return null;
        }
    }

    /**
     * 获取头信息
     *
     * @param token
     * @return
     */
    public static JwsHeader getHeaderBody(String token) {
        return getJws(token).getHeader();
    }

    /**
     * 校验令牌 是否有效
     *
     * @param token
     * @return 1 有效  0 无效  2 已过期
     */
    public static int verifyToken(String token) {

        try {
            Claims claims = AppJwtUtil.getClaimsBody(token);
            if (claims == null) {
                log.error("token：{}无效！！！", token);
                return SystemConstants.JWT_FAIL;
            }
            //log.info("token：{}校验成功！！！", token);
            return SystemConstants.JWT_OK;
        } catch (ExpiredJwtException ex) {
            log.error("token：{}已过期！！！", token);
            return SystemConstants.JWT_EXPIRE;
        } catch (Exception e) {
            log.error("token：{}无效！！！", token);
            return SystemConstants.JWT_FAIL;
        }
    }

    /**
     * 由字符串生成加密key
     *
     * @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.getEncoder().encode(TOKEN_ENCRYPT_KEY.getBytes());
        return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
    }


}
